package gang.org.springframework.framework.factory;

import gang.org.springframework.framework.bean.GangBeanWrapper;
import gang.org.springframework.framework.bean.GangBeanWrapperIml;
import gang.org.springframework.framework.bean.GangRootBeanDefinition;
import gang.org.springframework.framework.beanpostprocessor.GangBeanPostProcessor;
import gang.org.springframework.framework.beanpostprocessor.GangMergedBeanDefinitionPostProcessor;
import gang.org.springframework.framework.beanpostprocessor.GangSmartInstantiationAwareBeanPostProcessor;
import gang.org.springframework.framework.core.GangDefaultParameterNameDiscoverer;
import gang.org.springframework.framework.core.GangParameterNameDiscoverer;
import gang.org.springframework.framework.factory.config.GangAutowireCapableBeanFactory;
import gang.org.springframework.framework.support.*;
import gang.org.springframework.framework.util.GangClassUtils;
import gang.org.springframework.framework.util.GangObjectUtils;
import gang.org.springframework.framework.util.GangReflectionUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * @author gang.chen
 * @description
 * @Date 2021/6/16 19:09
 */
public abstract class GangAbstractAutowireCapableBeanFactory extends GangAbstractBeanFactory implements GangAutowireCapableBeanFactory {

    private GangInstantiationStrategy instantiationStrategy;

    private final ConcurrentMap<Class<?>, Method[]> factoryMethodCandidateCache = new ConcurrentHashMap<>();

    private final ConcurrentMap<String, GangBeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<>();

    public GangParameterNameDiscoverer parameterNameDiscoverer = new GangDefaultParameterNameDiscoverer();

    public GangAbstractAutowireCapableBeanFactory(){
        this.instantiationStrategy = new GangCglibSubclassingInstantiationStrategy();
    }

    @Override
    protected Object createBean(String beanName, GangRootBeanDefinition mbd, Object[] args) {
        //TODO
        GangRootBeanDefinition mbdToUse = mbd;

        //TODO Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

        //TODO Prepare method overrides.

        //TODO Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.

        try{
            Object beanInstance = doCreateBean(beanName,mbdToUse,args);
            return beanInstance;
        }catch (Exception e){
            //TODO
            throw e;
        }
    }

    /**
     * 业务意义
     * 1）创建一个Bean实例
     *
     * @param beanName bean名称
     * @param mbd BeanDefinition实例
     * @param args 主函数参数
     * */
    protected Object doCreateBean(String beanName, GangRootBeanDefinition mbd, Object[] args){

        /*
         * 实例化Bean
         * ************************************************
         * */
        GangBeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        //TODO
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != GangNullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        /*
         * 允许 post-processors 修改 bean 的定义
         * ************************************************
         * */
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        /*
         * 尽早的缓存单例对象，处理循环依赖
         * ************************************************
         * */
        boolean earlySingletonExposure = false;
        if (earlySingletonExposure) {
            //TODO
        }


        /*
         * 初始化bean 实例
         * ************************************************
         * */
        Object exposedObject = bean;
        try{
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch(Exception e){
            e.printStackTrace();
        }

        //TODO
        if (earlySingletonExposure) {

        }


        /*
         * 一次必注册bean
         * ************************************************
         * */
        try{
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }catch (Exception e){
            e.printStackTrace();
        }
        return exposedObject;
    }

    //TODO
    public void populateBean(String beanName, GangRootBeanDefinition mbd, GangBeanWrapper bw)
    {

    }

    //TODO
    public void applyMergedBeanDefinitionPostProcessors(GangRootBeanDefinition mbd, Class<?> beanType, String beanName){
        for (GangMergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
            processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }

    /**
     * 该方法的业务意义说明
     * */
    protected Object initializeBean(String beanName, Object bean, GangRootBeanDefinition mbd)
    {

        /*
         * TODO
         * 业务场景一
         * 1）回调Bean对象，所有实现的aware接口方法
         * 1.1）执行BeanNameAware接口方法setBeanName
         * 1.2）执行BeanClassLoaderAware接口方法setBeanClassLoader
         * 1.3）执行BeanFactoryAware接口方法setBeanFactory
         * */
        if (System.getSecurityManager() != null) {
            //TODO
        }else {
            invokeAwareMethods(null,null);
        }

        Object wrappedBean = bean;
        /*
         * TODO
         * 业务场景二
         * Bean对象在初始化之前，执行接口GangBeanPostProcessor方法postProcessBeforeInitialization
         * */
        if (mbd == null || !mbd.isSynthetic()) { //TODO
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean,beanName);
        }

        /*
         * TODO
         * 业务场景三
         * 3.1）Bean初始化时，如果实现了InitializingBean接口，执行方法afterPropertiesSet
         * 3.2）Bean初始化时，如果实现了Init方法执行该方法
         * */
        invokeInitMethods(beanName, bean, mbd);

        /*
         * 业务场景四
         * 4.1）Bean初化化最后，执行接口GangBeanPost
         * */
        applyBeanPostProcessorsAfterInitialization(bean, beanName);

        //TODO
        return wrappedBean;
    }

    private void invokeAwareMethods(String beanName, Object bean){
        //TODO
    }

    private Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName){
        Object result = existingBean;

        for (GangBeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {

            Object current = beanPostProcessor.postProcessBeforeInitialization(result, beanName);

            if (current == null){

                return result;
            }

            result = current;
        }
        return result;
    }

    protected void invokeInitMethods(String beanName, Object bean, GangRootBeanDefinition mbd){
        //TODO
    }

    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName){
        //TODO
        return null;
    }

    protected GangBeanWrapper createBeanWrapper(String beanName, GangRootBeanDefinition mbd, Object[] args){
        return instantiateBean(beanName,mbd);
    }

    protected GangBeanWrapper instantiateBean(String beanName, GangRootBeanDefinition mbd){
        //TODO
        Object beanInstance = getInstantiationStrategy().instantiate(mbd,beanName,this);

        //TODO
        GangBeanWrapper bw = new GangBeanWrapperIml(beanInstance);

        return bw;
    }



    public GangInstantiationStrategy getInstantiationStrategy() {
        return this.instantiationStrategy;
    }

    @Override
    protected String transformedBeanName(String name){
        return canonicalName(name);
    }


    /**
     * TODO 业务意义
     * 1）输入三个参数，beanName(Bean名称字符)mbd(BeanDefinition实例)typesToMatch(FactoryBean验证方法值为空)
     * 2）获取Beam字符名称对应的JAVA类
     * 2.1）Bean字符名称-方法
     * 2.2）Bean字符名称-JAVA类
     * @param beanName BeanDefinition 名称
     * @param mbd BeanDefinition实例
     * @param typesToMath 接口类
     * E.g BeanDefinition 名称：mvcResourceUrlProvider->GangResourceUrlProvider->继承自类GangApplicationListener GangApplicationListener接口类，为传入参数
     * (注：factoryBeanName先填充)
     *
     *  return Class
     * */
    @Override
    protected Class<?> predictBeanType(String beanName, GangRootBeanDefinition mbd, Class<?>... typesToMath) {
        //业务意义，获取到beanName(字符对应的实现类)
        Class<?> targetType = determineTargetType(beanName,mbd,typesToMath);
        return targetType;
    }

    /**
     * 业务意义
     * @param beanName BeanDefinition名称，由Springboot解析在于集合中(loop获取)
     * @param mbd BeanDefinition实例对象，与beanName对应
     * @param typesToMatch 指定接口名称
     * */
    protected Class<?> determineTargetType(String beanName,GangRootBeanDefinition mbd, Class<?>...typesToMatch){
        Class<?> targetType = mbd.getTargetType();
        if(targetType == null){
            /**
             * 业务意义
             * 场景一
             * 1）处理springboot内部特定类BeanDefinition, 工厂类BeanDefinition
             * 场景二
             * 2）处理工厂类中，方法注解@Bean
             * */
            targetType = mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch):resolveBeanClass(mbd,beanName,typesToMatch);


            //targetType = resolveBeanClass(mbd,beanName,typesToMatch);
            mbd.resolvedTargetType = targetType;
        }
        return targetType;
    }

    /**
     * 业务意义，通过实例来明确这个业务方法的业务
     * 1）springboot 解析spring.factories class字节码
     * 2）GangResourceUrlProvider@GangWebMvcConfigurationSupport#mvcResourceUrlProvider 该方法被解析为一个BeanDefinition
     * 3）方法#mvcResourceUrlProvider返回对象为 GangResourceUrlProvider
     * 4）目标就是获取 GangResourceUrlProvider
     * 5）最终返回的对象为：指定方法，E.g "mvcResourceUrlProvider",返回对象， E.g "GangResourceUrlProvider"
     * 6）所有的 beanName 都会被执行该操作
     * @param beanName BeanDefinition名称 E.g mvcResourceUrlProvider
     * @param typeToMatch 参数指定接口类 E.g gang.org.springframework.framework.context.GangApplicationListener
     * return Class
     * */
    protected Class<?> getTypeForFactoryMethod(String beanName, GangRootBeanDefinition mbd, Class<?>... typeToMatch){

        /*
         * GangResolvableType 业务意义不明确
         * 1）对Class类的封装
         * */
        GangResolvableType cachedReturnType = mbd.factoryMethodReturnType;

        Class<?> commonType = null;

        Method uniqueCandidate = mbd.factoryMethodToIntrospect;

        if (uniqueCandidate == null) {

            Class<?> factoryClass;
            /*
             * 业务意义
             * factoryBeanName，BeanDefinition创建该对象的工厂{@link gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration.GangEnableWebMvcConfiguration}
             * */
            String factoryBeanName = mbd.getFactoryBeanName();

            if (factoryBeanName != null) {
                //TODO factoryBeanName.equals(beanName))
                factoryClass = getType(factoryBeanName);
            }else {
                //TODO 静态方法处理
                factoryClass = resolveBeanClass(mbd, beanName, typeToMatch);

            }

            //TODO factoryClass = ClassUtils.getUserClass()
            //factoryClass = getType(factoryBeanName);
            factoryClass = GangClassUtils.getUserClass(factoryClass);

            /*
             * 业务意义？int minNrOfArgs TODO
             * 1，mbd.hasConstructorArgumentValues() 待编码 TODO，default return value is false
             * 2，mvcResourceUrlProvider -> mbd
             * 3，minNrOfArgs default value is 0
             * */
            int minNrOfArgs = mbd.hasConstructorArgumentValues() ? mbd.getConstructorArgumentValues().getArgumentCount() : 0;

            /*
             * 业务意义
             * 获取指定工厂类{@link gang.org.springframework.framework.web.servlet.GangWebMvcAutoConfiguration.GangEnableWebMvcConfiguration} 所有方法
             * */
            Method[] candidates = this.factoryMethodCandidateCache.computeIfAbsent(factoryClass, clazz -> GangReflectionUtils.getUniqueDeclaredMethods(clazz, GangReflectionUtils.USER_DECLARED_METHODS));

            for (Method candidate : candidates) {
                /**
                 * 业务场景判定4个条件
                 * */
                boolean isStatic = Modifier.isStatic(candidate.getModifiers());
                boolean factoryMethod = mbd.isFactoryMethod(candidate);
                boolean argumentsValuesSizeGigThen0 = candidate.getParameterCount() >= minNrOfArgs;


                if (candidate.getTypeParameters().length>0) {
                    //TODO
                }else{
                    uniqueCandidate = commonType ==null ? candidate : null;

                    /*
                     * 业务意义,重点处理方法：mvcResourceUrlProvider
                     * 1）candidate实际对象是Method
                     * 2）returnType 方法返回对象 {@link gang.org.springframework.framework.web.servlet.config.annotation.GangWebMvcConfigurationSupport}
                     * 3）commonType 此场景下为空
                     * */
                    commonType = GangClassUtils.determineCommonAncestor(candidate.getReturnType(), commonType);
                    if (commonType == null) {
                        return null;
                    }
                }
            }

            /*
             * 业务意义
             * 1）mbd 是对方法创建的Bean对象描述
             *   -> mbd = public GangResourceUrlProvider mvcResourceUrlProvider()
             *   -> mbd.factoryMethodToIntrospect = GangWebmvcConfigurationSupport
             *
             * */
            mbd.factoryMethodToIntrospect = uniqueCandidate;
        }
        /*
         * 业务意义
         * 1）获取到一个ResolvableType类，该对象是对Class类的封装
         * */
        cachedReturnType = uniqueCandidate != null? GangResolvableType.forMethodReturnType(uniqueCandidate): GangResolvableType.forClass(commonType);
        mbd.factoryMethodReturnType = cachedReturnType;
        return cachedReturnType.resolve();
    }

    protected GangBeanWrapper createBeanInstance(String beanName, GangRootBeanDefinition mbd, Object[] args){
        /**
         * 业务意义
         * 1）通过类加载器，获取beanName对应的实体类
         * */
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        /**
         * if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed())
         * */
        //TODO

        /**
         * Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
         * if (instanceSupplier != null)
         * */
        //TODO


        /**
         * if (mbd.getFactoryMethodName() != null)
         * */
        //TODO


        /**
         * 实例
         * 1）tomcatServletWebServerFactory 该bean由工厂类(EmbeddedTomcat)来创建
         * */
        if (mbd.getFactoryMethodName() != null){
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        /**
         * Shortcut when re-creating the same bean...
         * */
        boolean resolved = false;
        boolean autowiredNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    //TODO
                }
            }
        }
        if (resolved) {
            //TODO
        }

        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors!=null || mbd.getResolvedAutowireMode() == autowire_constructor || mbd.hasConstructorArgumentValues()|| !GangObjectUtils.isEmpty(args)) {
            return autowireConstructor(beanName, mbd, ctors, args);
        }


        /**
         * 实例
         * 1）EmbeddedTomcat实例bean，由EmbeddedTomcat无参数构造方法创建
         *
         * */
        return instantiateBean(beanName, mbd);
    }

    protected GangBeanWrapper instantiateUsingFactoryMethod(String beanName, GangRootBeanDefinition mbd, Object[] explicitArgs){

        return new GangConstructorResolver(this).instantiatedUsingFactoryMethod(beanName, mbd, explicitArgs);
    }

    protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName){
        if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
            for (GangSmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
                Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
                if (ctors != null) {
                    return ctors;
                }
            }
        }
        return null;
    }

    public GangBeanWrapper autowireConstructor(String beanName,
                                               GangRootBeanDefinition mbd,
                                               Constructor<?>[] ctors,
                                               Object[] explicitArgs){
        return new GangConstructorResolver(this).autowireConstructor(beanName, mbd, ctors,explicitArgs);
    }

    public GangParameterNameDiscoverer getParameterNameDiscoverer(){
        return this.parameterNameDiscoverer;
    }
}
